Skip to content

fix: URL-encode special characters in connection string passwords#597

Merged
anandgupta42 merged 2 commits intoAltimateAI:mainfrom
VJ-yadav:fix/special-char-passwords
Apr 5, 2026
Merged

fix: URL-encode special characters in connection string passwords#597
anandgupta42 merged 2 commits intoAltimateAI:mainfrom
VJ-yadav:fix/special-char-passwords

Conversation

@VJ-yadav
Copy link
Copy Markdown
Contributor

@VJ-yadav VJ-yadav commented Mar 30, 2026

Summary

Fixes #589 — stored passwords with special characters (@, #, :, /, etc.) cause cryptic authentication failures when used in URI-style connection strings.

  • Root cause: sanitizeConnectionString() existed in normalize.ts but was never called — connection strings with unencoded passwords were passed directly to drivers
  • Regex bug: The userinfo regex split on the first @ instead of the last, so passwords containing @ were silently mis-parsed (the function returned early thinking no encoding was needed)
  • Fix: Wire sanitizeConnectionString() into normalizeConfig() so every driver that accepts a connection_string benefits automatically, and fix the regex to use greedy matching for the userinfo portion

Drivers using individual config fields (host, user, password as separate values) are unaffected — native driver libraries handle raw passwords correctly without URI encoding.

Test Plan

  • Added 16 new test cases covering sanitizeConnectionString directly and normalizeConfig integration
  • Passwords with @, #, : are correctly percent-encoded
  • Already-encoded passwords (%40, %23) are left untouched
  • Passwords without special characters pass through unchanged
  • Non-URI connection strings (e.g. Oracle TNS, key=value) pass through unchanged
  • mongodb://, mongodb+srv://, postgresql:// schemes all handled
  • Config without connection_string (individual fields) is not altered
  • connectionString alias resolves to connection_string before sanitization
  • All 121 existing + new tests pass

Checklist

  • Minimal, focused change — no unrelated modifications
  • All existing tests continue to pass (121/121)
  • Pre-existing tsgo error on @clickhouse/client import is unrelated (reproduces on main)

Summary by CodeRabbit

  • New Features

    • Connection strings with credentials containing special characters (e.g., @, #, :, /, ?) are now automatically percent-encoded during configuration normalization.
    • A public utility to sanitize connection strings is now exposed for direct use.
  • Tests

    • Added unit and integration tests covering sanitization, no-op cases, malformed inputs, ambiguity edge cases, and integration with normalization.

Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@github-actions
Copy link
Copy Markdown

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a89ce366-c9e1-4c66-9880-55d3850ca19a

📥 Commits

Reviewing files that changed from the base of the PR and between aa2d643 and 0d47365.

📒 Files selected for processing (3)
  • packages/drivers/src/index.ts
  • packages/drivers/src/normalize.ts
  • packages/opencode/test/altimate/driver-normalize.test.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/opencode/test/altimate/driver-normalize.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/drivers/src/normalize.ts

📝 Walkthrough

Walkthrough

Adds sanitizeConnectionString to the drivers package, a function that percent-encodes unsafe characters in URI userinfo (user/password) and is invoked from normalizeConfig. The helper is exported from the package entry and covered by unit and integration tests.

Changes

Cohort / File(s) Summary
Driver Normalization
packages/drivers/src/normalize.ts
Added exported sanitizeConnectionString(connectionString: string): string that detects scheme-based URIs, locates userinfo, idempotently decodes+re-encodes user and password, guards against ambiguous @ cases, and returns original string when unchanged; normalizeConfig now applies this sanitizer to result.connection_string when it's a string.
Package Exports
packages/drivers/src/index.ts
Re-exports the new sanitizeConnectionString alongside existing exports (e.g., normalizeConfig).
Tests
packages/opencode/test/altimate/driver-normalize.test.ts
Added unit tests covering encoding for postgresql://, mongodb://, mongodb+srv://, no-op cases, malformed percent-encodings, ambiguity cases with @ in query/path/fragment, and integration tests asserting normalizeConfig sanitizes connection_string and respects connectionString alias.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇
I found a string with secrets snug and tight,
% and @ made my whiskers twitch at night.
I nibble, encode, then hop away with care,
Hosts untouched, passwords safe in my lair.
🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is comprehensive and follows the template structure with Summary, Test Plan, and Checklist sections. However, it does not include the required PINEAPPLE identifier at the top as mandated for AI-generated contributions. Add the word PINEAPPLE at the very top of the PR description before any other content, as required by the template for AI-generated contributions.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: fixing URL encoding of special characters in connection string passwords, directly addressing the core issue.
Linked Issues check ✅ Passed The PR successfully addresses issue #589 by implementing percent-encoding of special characters in URI-style connection string passwords, fixing the root cause and regex bug while preserving non-URI formats.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing special character handling in connection strings: adding sanitizeConnectionString export, implementing the sanitization logic with regex fix, and comprehensive test coverage. No unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gitguardian
Copy link
Copy Markdown

gitguardian bot commented Mar 30, 2026

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/drivers/src/normalize.ts (1)

161-163: Potential URIError if username contains malformed percent sequences.

decodeURIComponent(user) will throw a URIError if the username contains malformed percent-encoded sequences (e.g., user%GGname). While rare, this could cause unexpected failures.

Consider wrapping in try-catch or skipping the decode/re-encode cycle for the username when it doesn't contain %:

🛡️ Proposed defensive fix
-  // Re-encode both user and password to be safe
-  const encodedUser = encodeURIComponent(decodeURIComponent(user))
+  // Re-encode both user and password to be safe.
+  // If user contains %, attempt decode; otherwise encode directly.
+  let encodedUser: string
+  try {
+    encodedUser = encodeURIComponent(decodeURIComponent(user))
+  } catch {
+    // Malformed percent sequence — encode as-is
+    encodedUser = encodeURIComponent(user)
+  }
   const encodedPassword = encodeURIComponent(password)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/drivers/src/normalize.ts` around lines 161 - 163, The
decode/re-encode of the username using decodeURIComponent(user) can throw a
URIError for malformed percent sequences; update the logic around encodedUser
(where decodeURIComponent(user) and encodeURIComponent are used) to first check
if user contains '%' and only perform decode/encode when safe, or wrap
decodeURIComponent(user) in a try-catch and fall back to using the original user
string if decoding fails, ensuring encodedUser is always set to a valid
encodeURIComponent value without throwing.
packages/opencode/test/altimate/driver-normalize.test.ts (1)

974-978: Consider adding test coverage for / and ? in passwords.

The PR objectives mention handling / as a special character, and the implementation's regex also includes ?. Adding explicit tests would strengthen coverage:

📝 Suggested additional tests
test("encodes / in password", () => {
  const input = "postgresql://admin:pass/word@localhost/db"
  const result = sanitizeConnectionString(input)
  expect(result).toBe("postgresql://admin:pass%2Fword@localhost/db")
})

test("encodes ? in password", () => {
  const input = "postgresql://admin:pass?word@localhost/db"
  const result = sanitizeConnectionString(input)
  expect(result).toBe("postgresql://admin:pass%3Fword@localhost/db")
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/altimate/driver-normalize.test.ts` around lines 974 -
978, Add two unit tests to the existing "encodes multiple special characters"
suite that verify sanitizeConnectionString correctly percent-encodes '/' and '?'
inside the password portion: create one test using input
"postgresql://admin:pass/word@localhost/db" expecting
"postgresql://admin:pass%2Fword@localhost/db" and another using
"postgresql://admin:pass?word@localhost/db" expecting
"postgresql://admin:pass%3Fword@localhost/db"; place these tests alongside the
existing tests in driver-normalize.test.ts to ensure sanitizeConnectionString
handles both characters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/drivers/src/normalize.ts`:
- Around line 161-163: The decode/re-encode of the username using
decodeURIComponent(user) can throw a URIError for malformed percent sequences;
update the logic around encodedUser (where decodeURIComponent(user) and
encodeURIComponent are used) to first check if user contains '%' and only
perform decode/encode when safe, or wrap decodeURIComponent(user) in a try-catch
and fall back to using the original user string if decoding fails, ensuring
encodedUser is always set to a valid encodeURIComponent value without throwing.

In `@packages/opencode/test/altimate/driver-normalize.test.ts`:
- Around line 974-978: Add two unit tests to the existing "encodes multiple
special characters" suite that verify sanitizeConnectionString correctly
percent-encodes '/' and '?' inside the password portion: create one test using
input "postgresql://admin:pass/word@localhost/db" expecting
"postgresql://admin:pass%2Fword@localhost/db" and another using
"postgresql://admin:pass?word@localhost/db" expecting
"postgresql://admin:pass%3Fword@localhost/db"; place these tests alongside the
existing tests in driver-normalize.test.ts to ensure sanitizeConnectionString
handles both characters.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 44b3dc65-0c0f-455e-ab26-0eacd895c951

📥 Commits

Reviewing files that changed from the base of the PR and between 99270e5 and 93db0f4.

📒 Files selected for processing (3)
  • packages/drivers/src/index.ts
  • packages/drivers/src/normalize.ts
  • packages/opencode/test/altimate/driver-normalize.test.ts

@VJ-yadav VJ-yadav force-pushed the fix/special-char-passwords branch 2 times, most recently from ea99829 to 40886f2 Compare April 3, 2026 06:11
@dev-punia-altimate
Copy link
Copy Markdown

❌ Tests — Failures Detected

TypeScript — 15 failure(s)

  • connection_refused [2.53ms]
  • timeout [2.42ms]
  • permission_denied [2.71ms]
  • parse_error [2.39ms]
  • oom [2.64ms]
  • network_error [2.74ms]
  • auth_failure [2.69ms]
  • rate_limit [2.88ms]
  • internal_error [2.90ms]
  • empty_error [0.25ms]
  • connection_refused [0.13ms]
  • timeout [0.07ms]
  • permission_denied [0.07ms]
  • parse_error [0.06ms]
  • oom [0.07ms]

cc @VJ-yadav
Tested at 40886f25 | Run log | Powered by QA Autopilot

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/drivers/src/normalize.ts`:
- Around line 150-152: The current early-return on /%[0-9A-Fa-f]{2}/ prevents
addressing mixed raw/encoded passwords (e.g., "myp%40ss@word"); instead of
returning connectionString when that regex matches, decode the password (use
decodeURIComponent on the extracted password), then unconditionally re-encode
the decoded value (via encodeURIComponent) and substitute that encodedPassword
back into connectionString; remove the early-return on the regex, ensure you
operate on the password variable (or decodedPassword) and write the encoded
result into the connection string where the password is inserted (the code paths
around the existing password, connectionString and the later encoding
replacement on line ~170).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: be01ceb1-6695-4d50-b1c0-f0cfb65f47ed

📥 Commits

Reviewing files that changed from the base of the PR and between 93db0f4 and 860b115.

📒 Files selected for processing (3)
  • packages/drivers/src/index.ts
  • packages/drivers/src/normalize.ts
  • packages/opencode/test/altimate/driver-normalize.test.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/drivers/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/opencode/test/altimate/driver-normalize.test.ts

@anandgupta42
Copy link
Copy Markdown
Contributor

Review — Ready for merge

Scope: Fixes user-reported bug #589 — stored passwords with special characters (@, #, :, /) cause cryptic auth failures because the URI-style connection string was passed through unencoded.

Analysis

  • Root-cause diagnosis is correct: sanitizeConnectionString() existed in normalize.ts but was never wired into normalizeConfig()
  • Regex fix is important: userinfo split now uses greedy (.+)@([^@]+)$ (last @) instead of first-@ split — this was the silent bug where passwords containing @ got mis-parsed
  • Defensive handling is sound:
    • Already-encoded passwords (%XX sequences) are left untouched — idempotent
    • decodeURIComponent wrapped in try/catch with raw-encode fallback for malformed input
    • Non-URI connection strings (Oracle TNS, key=value) pass through unchanged
    • Drivers using individual config fields are unaffected — only connection_string is sanitized
  • Single integration point in normalizeConfig() means every URI-based driver benefits automatically (postgres, mongodb, clickhouse, redshift…)

Files changed (3): drivers/src/index.ts (export), drivers/src/normalize.ts (fix + function), tests (+202, -2)

CI status (commit 40886f25)

  • ✅ TypeScript, Driver E2E, anti-slop, check-standards, Marker Guard, GitGuardian — all green
  • ⚠️ centralized-test-results shows the same generic 15 failures appearing identically on every open PR in this batch — pre-existing altimate-qa flakiness, not caused by this PR

Minor observations (non-blocking)

  • Character set /[@:#/?[\]%]/ check is correct but could also include & and space for belt-and-suspenders; current set catches all common breakage
  • Could add JSDoc @example showing before/after sanitization — cosmetic only

Recommendation
Ready for merge — rebase on main (BEHIND) and this should go in. Real user pain fix with good test coverage.

cc @anandgupta42 — ready for /release once rebased.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/drivers/src/normalize.ts (1)

150-152: ⚠️ Potential issue | 🟠 Major

Remove %XX early return; handle mixed encoded/raw passwords.

Line 152 exits too early when any encoded byte is present. Passwords with both encoded and raw special chars remain partially unencoded and still break parsing.

Suggested fix
-  // If the password already contains percent-encoded sequences, assume
-  // the caller encoded it properly and leave it alone.
-  if (/%[0-9A-Fa-f]{2}/.test(password)) return connectionString
+  let decodedPassword = password
+  try {
+    decodedPassword = decodeURIComponent(password)
+  } catch {
+    // malformed percent sequence; treat as raw
+    decodedPassword = password
+  }

-  const needsEncoding = /[@:`#/`?[\]%]/.test(password)
-  if (!needsEncoding) return connectionString
+  const needsEncoding = /[@:`#/`?[\]%]/.test(decodedPassword)
+  if (!needsEncoding && decodedPassword === password) return connectionString
...
-  const encodedPassword = encodeURIComponent(password)
+  const encodedPassword = encodeURIComponent(decodedPassword)

Also applies to: 158-170

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/drivers/src/normalize.ts` around lines 150 - 152, Remove the early
return that bails out when /%[0-9A-Fa-f]{2}/ matches and instead transform the
password so existing percent-encoded triplets are preserved while any raw
special characters are percent-encoded; specifically update the logic that
currently checks the regex against password (the if (/%[0-9A-Fa-f]{2}/) return
connectionString) to iterate the password string, copy any "%XX" sequences
unchanged and percent-encode other characters (e.g., via encodeURIComponent on
single chars or a small stateful loop), then reconstruct connectionString with
the safely-encoded password; apply the same change to the other similar block
around the later password-handling code (the 158-170 region) so mixed
encoded/raw passwords are fully handled.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/drivers/src/normalize.ts`:
- Around line 136-138: The regex used to split userinfo from host in
normalize.ts (variable uriMatch matching connectionString) is greedy and can
cross into query/fragment when those contain '@'; update the pattern so the
userinfo capture is constrained to the authority segment (stop at '/', '?' or
'#'). Concretely, replace the (.+) group in the existing regex with a character
class that excludes '/', '?', and '#' (e.g., ([^\/?#]+)) so uriMatch only
considers the authority portion of connectionString when locating the '@'.

---

Duplicate comments:
In `@packages/drivers/src/normalize.ts`:
- Around line 150-152: Remove the early return that bails out when
/%[0-9A-Fa-f]{2}/ matches and instead transform the password so existing
percent-encoded triplets are preserved while any raw special characters are
percent-encoded; specifically update the logic that currently checks the regex
against password (the if (/%[0-9A-Fa-f]{2}/) return connectionString) to iterate
the password string, copy any "%XX" sequences unchanged and percent-encode other
characters (e.g., via encodeURIComponent on single chars or a small stateful
loop), then reconstruct connectionString with the safely-encoded password; apply
the same change to the other similar block around the later password-handling
code (the 158-170 region) so mixed encoded/raw passwords are fully handled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 66bfd234-ca6a-4056-a795-2527aead9488

📥 Commits

Reviewing files that changed from the base of the PR and between 860b115 and aa2d643.

📒 Files selected for processing (3)
  • packages/drivers/src/index.ts
  • packages/drivers/src/normalize.ts
  • packages/opencode/test/altimate/driver-normalize.test.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/drivers/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/opencode/test/altimate/driver-normalize.test.ts

Fixes AltimateAI#589 — stored passwords with special characters (`@`, `#`, `:`, `/`)
cause cryptic authentication failures when used in URI-style connection
strings because the userinfo section wasn't being percent-encoded.

Root cause:
- `sanitizeConnectionString()` existed in `normalize.ts` but was never
  wired into `normalizeConfig()` — connection strings with unencoded
  passwords went directly to drivers
- The userinfo regex split on the *first* `@` instead of the *last*, so
  passwords containing `@` were silently mis-parsed and the function
  returned early thinking no encoding was needed

Fix:
- Wire `sanitizeConnectionString()` into `normalizeConfig()` as a single
  integration point so every URI-based driver benefits automatically
- Fix the regex to use greedy matching for the userinfo portion and
  split on the last `@` before the host
- Leave already-encoded passwords (`%XX` sequences) untouched for
  idempotency; decodeURIComponent wrapped in try/catch for safety

Non-URI connection strings (Oracle TNS, key=value) and drivers using
individual config fields (host/user/password) are unaffected — the
fix only touches `connection_string`.

Tests cover @/#/:/ in passwords, already-encoded passthrough, multiple
URI schemes (postgresql://, mongodb://, mongodb+srv://), and the
connectionString alias path.
@anandgupta42 anandgupta42 force-pushed the fix/special-char-passwords branch from aa2d643 to 258a4cb Compare April 5, 2026 06:49
Multi-model code review flagged three real bugs in sanitizeConnectionString:

1. CRITICAL — greedy regex corrupted URIs with '@' in query/path
   Example: postgresql://u:p@host/db?email=alice@example.com
   Rightmost '@' was in the query string, not the userinfo separator.
   The sanitizer treated host/db?email=alice as part of the password and
   percent-encoded it, producing a broken URI.

2. MAJOR — short-circuit on %XX skipped passwords with mixed encoding
   Example: postgresql://user:p%20ss@word@host/db
   Partially-encoded password contained both a valid %20 and a raw '@'.
   The 'already-encoded, leave alone' check bailed early and left '@'
   unencoded.

3. MINOR — username-only userinfo (no colon) was skipped entirely
   Example: postgresql://alice@example.com@host/db
   Email-as-username with unencoded '@' broke URI parsing because we
   returned early on missing colon.

Changes:
- Scan for the LAST '@' in the afterScheme portion directly instead of
  first parsing out an 'authority' segment. The URI spec disallows
  unencoded path/query/fragment delimiters in authority, but real-world
  passwords do contain them — so we honor user intent over spec.
- Replace the %XX short-circuit + needsEncoding pre-check with a single
  idempotent encoder (decode → encode) applied to both user and password
  components. This round-trips already-encoded values unchanged and
  encodes raw values correctly in one pass.
- Handle username-only userinfo by encoding it when no colon is present.
- Add an ambiguity guard: when the rightmost '@' is followed by no
  path/query/fragment delimiter but preceded by one, the '@' is in the
  query/path/fragment — return the URI unchanged and expect the caller
  to pre-encode.

Test coverage added for all three bugs plus IPv6 hosts, URIs with no
port, URIs with no path, path-with-@, fragment-with-@, and the
ambiguous both-password-and-query-have-@ case.
@anandgupta42
Copy link
Copy Markdown
Contributor

Consensus code-review applied — fixes pushed

Ran a 4-participant consensus review (Claude + GPT 5.4 + Gemini 3.1 Pro + self-review) and applied all flagged fixes.

Real bugs found and fixed

1. CRITICAL — greedy regex corrupted URIs with @ in query/path (Gemini)

  • postgresql://u:p@host/db?email=alice@example.com — the rightmost @ was in the query string, not the userinfo separator. The sanitizer treated host/db?email=alice as part of the password and percent-encoded it, producing a broken URI.

2. MAJOR — %XX short-circuit skipped passwords with mixed encoding (both models)

  • postgresql://user:p%20ss@word@host/db — partially-encoded password contained both %20 and raw @. The "already-encoded, leave alone" check bailed early and left @ unencoded.

3. MINOR — username-only userinfo skipped entirely (Gemini)

  • postgresql://alice@example.com@host/db — email-as-username with unencoded @ broke URI parsing because the function returned early when no colon was present.

Fix approach

  • Rewrite the parser to scan for the LAST @ in afterScheme directly rather than first extracting an "authority" segment. The URI spec disallows unencoded path/query/fragment delimiters in authority, but real-world passwords do contain them — honoring user intent over spec.
  • Replace the %XX short-circuit + needsEncoding pre-check with a single idempotent encoder (decode → encode) applied to both user and password components. Round-trips already-encoded values unchanged and encodes raw values in one pass.
  • Handle username-only userinfo by encoding it when no colon is present.
  • Add an ambiguity guard: when the rightmost @ is preceded by /?# but not followed by any delimiter, it's in a query/path/fragment — return the URI untouched and expect the caller to pre-encode.

Test coverage added

11 new tests covering: @ in query string, path, fragment; username-only with @; partially-encoded password with raw @, #; malformed percent sequences; no-port URIs; no-path URIs; and the ambiguous case where both password AND query contain @.

134 driver-normalize tests pass. TypeScript clean. All CI green.

Pushed as 0d473659d5. Ready for merge.

@anandgupta42 anandgupta42 merged commit 29e4267 into AltimateAI:main Apr 5, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stored passwords with special characters do not work

3 participants